#include <stdio.h>
#include <stdlib.h>


int main(int argc, char const *argv[])
{
    // int a = 10;
    // int b = 20;
    // int* c = &a;//将指针指向a,c这个变量里面存的是a的地址
    // *c = 30;//改变c存的地址所处位置的值
    // printf("a的地址是%p,其值为%d\n",c,*c);
    
    // c = &b;//改变指针的指向,将c里面的值改变成b的地址
    // *c = 50;//改变c存的地址所处位置的值
    // printf("b的地址是%p,其值为%d\n",c,*c);

    // const int *q = &a;
    // q = &b;
    // //*q = 1;const修饰了*q,所以*q的值不能被修改,但是q的值可以修改,*q的值是储存地址所在位置的值,q是储存的地址
    // printf("q存储的地址是%p,其值为%d\n",q,*q);
    // int* const w = &b;
    // //w = &a;const修饰了w,所以w的值不能被修改,但是*w的值可以修改,*w的值是储存地址所在位置的值,w是储存的地址
    // *w = 2;
    // printf("w存储的地址是%p,其值为%d\n",w,*w);
    // int const * const e = &a;
    // //e = &b;
    // //*e = 3;因为const修饰了*和e,所以e的值和*e的值都不能被修改
    // printf("e存储的地址是%p,其值为%d\n",e,*e);

    // int num[3] = {1,2,3};
    // int *r = num;
    // printf("num第一个值是%d\n",*r);
    // printf("num第一个值是%d\n",num[0]);
    // printf("num第二个值是%d\n",*(r+1));
    // printf("num第二个值是%d\n",num[1]);
    // printf("num第三个值是%d\n",*(r+2));
    // printf("num第三个值是%d\n",num[2]);

    // int a = 111;
    // printf("%p\n",a);//无法直接打印变量的地址,这个的结果是0x6f,也就是16进制的结果
    // printf("%p\n",&a);//&符取地址后能顺利的打印出来
    // int a[3] = {10,5,4};//数组名称a本身就储存着整个数组的第一个元素的地址,也就是首地址
    // printf("%p\n",a);//所以这里直接取地址就可以打印出来,只是打印出的是数组里面所有元素第一个的首地址:da0
    // printf("%p\n",&a);//也可以用&符取,这个是取整个数组的首地址:da0,不分元素的区别,在下面两条就能体现
    // printf("%p\n",a+1);//这个地址取出来结尾是da4,这个是在数组元素的基础上+1,因为元素是int型,所以+1会往后加四个字节
    // printf("%p\n",&a+1);//这个地址取出来结尾是dac,这个是在整个数组的基础上+1,因为数组有三个int元素,所以+1会往后加12个字节
    
    /*char a[10] = "ABCDEFG";//字符数组,也就是存一个字符串,结尾默认添加一个\0结束,在指针层面,数组名字a就储存着这个数组的首地址
    char *a_p ="abcdefg";//直接使用指针定义一个字符数组,与上面的字符数组等效
    printf("%s\n",a);
    printf("%s\n",a+1);
    printf("%s\n",a_p);
    printf("%s\n",a_p+1);//目前不管,就当是同一种东西
    //%s是打印剩下的字符,在打印时不需要加*号,打印某个字符时,就需要加*号了,例如以下代码:
    printf("%c\n",*a+1);
    printf("%c\n",*a_p+1);*/

    /*//二维数组与指针:
     int a[3][2] = {{1,2},{3,4},{5,6}};//a为数组的名字,储存的地址是三组元素的首地址的第一个元素的地址,也就是1的地址
    // printf("%d\n",a[2][1]);
    // printf("%d\n",*(*(a+2)+1));
    // printf("%p  %p  %p\n",a,a+1,a+2);
    //由上可知a[2][1]等效于*(*(a+2)+1),首先a记录的是数组每组元素首地址的首地址,地址是8个字节,那么a+1也就是在原地址上加8个字节
    //然后a+2就是索引到了第三组元素的首元素的地址,这时候取出a+2的地址就变成了数组内的元素了,再+1就是加上元素的类型字节数,也就是4字节
    //最后再用*取出,就是跟a[2][1]一样为6了
    //使用指针一个循环打印二维数组:
    int *p = &a[0][0];
    for (int i = 0; i < 2*3; i++)
    {
        printf("%d\n",*(p+i));
    }
    //使用指针两个循环打印二维数组:
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 2; j++)
        {
            printf("%d  ",*(*(a+i)+j));
        }
        printf("\n");
    }*/
    /*问:a[0]是什么
       *(&a[0]+1)取出来的数是什么
       答:a[0]是整个数组的第一个数,也就是1
       a首先是数组三组元素的首地址的首地址,所以a[0]记录的是第一组元素的首地址,而地址的存储是8个字节,所以
       &a[0]+1就是在第一组元素的首地址上加上8个字节,按照字节顺序就是这个数组的第三个元素的位置,也就是3*/
    
    int a[3][2] = {{1,2},{3,4},{5,6}};
    int (*p)[2] = a;/*无法直接用int *p=a这个来指向a这个二维数组,需要使用 int (*p)[2] = a来让指针指向
    分组后的首地址,并且[2]表示每个地址包含两个元素,这种就叫做数组指针
    int (*p)[2] = &a 指针的类型是int [2],p+1就是往后跳两个int,这个可以使用在一维数组快速分格上*/
    return 0;
}
